package com.hmall.search.service.impl;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.TotalHits;
import co.elastic.clients.json.JsonData;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hmall.common.domain.PageDTO;
import com.hmall.search.domain.po.ItemDoc;
import com.hmall.search.domain.query.ItemPageQuery;
import com.hmall.search.service.ISearchService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author lee
 * @version 1.0
 * @description 搜索接口实现类
 */
@Service
@Slf4j
@AllArgsConstructor
public class ISearchServiceImpl implements ISearchService {

    private final ElasticsearchClient esClient;

    @Override
    public PageDTO<ItemDoc> query(ItemPageQuery query) {

        try {
            SearchRequest.Builder builder = new SearchRequest.Builder();
            builder
                    .query(q -> q.bool(b -> {
                                b.must(b1 -> {
                                    //如果搜索关键字不为空
                                    if (StringUtils.isNotEmpty(query.getKey())) {
                                        b1.multiMatch(m -> m
                                                .query(query.getKey())
                                                .fields("name", "brand", "category", "spec"));
                                    } else {
                                        //查询所有记录
                                        b1.matchAll(m -> m);
                                    }
                                    return b1;
                                });
                                if (StringUtils.isNotEmpty(query.getCategory())) {
                                    b.filter(f -> f.term(t -> t.field("category").value(query.getCategory())));
                                }
                                //品牌
                                if (StringUtils.isNotEmpty(query.getBrand())) {
                                    b.filter(f -> f.term(t -> t.field("brand").value(query.getBrand())));
                                }
                                //价格
                                if (query.getMinPrice() != null && query.getMaxPrice() != null) {
                                    b.filter(f -> f.range(r -> r.field("price").gte(JsonData.of(query.getMinPrice())).lte(JsonData.of(query.getMaxPrice()))));
                                }
                                return b;
                            }
                    ))
                    .size(query.getPageSize())
                    .from(query.from());
            //指定索引
            builder.index("items");
            //排序
            if (StringUtils.isNotEmpty(query.getSortBy())) {
                builder.sort(sort -> sort.field(f -> f.field(query.getSortBy()).order(query.getIsAsc() ? SortOrder.Asc : SortOrder.Desc)));
            }
            //高亮
            builder.highlight(h -> h
                    .fields("name", f -> f
                            .preTags("<em>")
                            .postTags("</em>")));
            //构建请求
            SearchRequest build = builder.build();
            //发送请求
            SearchResponse<ItemDoc> response = esClient.search(build, ItemDoc.class);

            //解析响应
            //匹配的总数量
            TotalHits total = response.hits().total();
            //获取结果列表
            List<Hit<ItemDoc>> hits = response.hits().hits();
            //转为List<ItemDoc>
            List<ItemDoc> itemDocs = hits.stream().map(hit -> {
                ItemDoc source = hit.source();
                //解析高亮结果
                Map<String, List<String>> highlightFields = hit.highlight();
                if (highlightFields != null) {
                    List<String> name = highlightFields.get("name");
                    if (name != null) {
                        String highlightName = name.get(0);
                        source.setName(highlightName);
                    }
                }
                return source;
            }).collect(Collectors.toList());
            Page<ItemDoc> page = Page.of(query.getPageNo(), query.getPageSize(), total.value());
            PageDTO<ItemDoc> pageDTO = PageDTO.of(page);
            pageDTO.setList(itemDocs);
            return pageDTO;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取建议
     *
     * @param prefix
     * @return
     */
    @Override
    public List<String> getSuggestions(ItemPageQuery prefix) {
        try {
            SearchRequest.Builder builder = new SearchRequest.Builder();
            builder
                    .query(q -> q.bool(b -> {
                                b.must(b1 -> {
                                    //如果搜索关键字不为空
                                    if (StringUtils.isNotEmpty(prefix.getKey())) {
                                        b1.multiMatch(m -> m
                                                .query(prefix.getKey())
                                                .fields("name", "brand", "category", "spec"));
                                    } else {
                                        //查询所有记录
                                        b1.matchAll(m -> m);
                                    }
                                    return b1;
                                });
                                if (StringUtils.isNotEmpty(prefix.getCategory())) {
                                    b.filter(f -> f.term(t -> t.field("category").value(prefix.getCategory())));
                                }
                                //品牌
                                if (StringUtils.isNotEmpty(prefix.getBrand())) {
                                    b.filter(f -> f.term(t -> t.field("brand").value(prefix.getBrand())));
                                }
                                //价格
                                if (prefix.getMinPrice() != null && prefix.getMaxPrice() != null) {
                                    b.filter(f -> f.range(r -> r.field("price").gte(JsonData.of(prefix.getMinPrice())).lte(JsonData.of(prefix.getMaxPrice()))));
                                }
                                return b;
                            }
                    ))
                    .size(prefix.getPageSize())
                    .from(prefix.from());
            //指定索引
            builder.index("items");
            //排序
            if (StringUtils.isNotEmpty(prefix.getSortBy())) {
                builder.sort(sort -> sort.field(f -> f.field(prefix.getSortBy()).order(prefix.getIsAsc() ? SortOrder.Asc : SortOrder.Desc)));
            }
            //高亮
            builder.highlight(h -> h
                    .fields("name", f -> f
                            .preTags("<em>")
                            .postTags("</em>")));
            //构建请求
            SearchRequest build = builder.build();
            //发送请求
            SearchResponse<ItemDoc> response = esClient.search(build, ItemDoc.class);
            //TODO 解析响应
        }catch (IOException e) {
            e.printStackTrace();
        }
        return List.of();
    }
}
